package com.loongson;

import org.openstack4j.api.Builders;
import org.openstack4j.api.OSClient.OSClientV3;
import org.openstack4j.model.common.ActionResponse;
import org.openstack4j.model.common.Identifier;
import org.openstack4j.model.compute.Server;
import org.openstack4j.model.compute.FloatingIP;
import org.openstack4j.model.compute.ServerCreate;
import org.openstack4j.model.network.NetFloatingIP;
import org.openstack4j.openstack.OSFactory;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

import org.openstack4j.model.compute.VNCConsole;
import org.openstack4j.model.compute.VNCConsole.Type;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
;

public class OpenstackUtil {

	private static Logger logger = LoggerFactory.getLogger(OpenstackUtil.class);
	private String url = null;
	private String username = null;
	private String password = null;
	private String domain = null;
	private String projectId = null;
	//private String imageId = "a02b7c3f-973a-4305-9c2a-abb210f49313";//loongnix server
	private String imageId = null;//uos server
	private String networkId = null;
	private String flavorId = "1";
	List<String> networks = new ArrayList<String>();

	ArrayList<VmInfo> vmInfoList = new ArrayList<VmInfo>();
	Properties properties;


	private OSClientV3 os;

	
	//read configuration from a file 
	public void loadConfig(String path){

		logger.info("Load config:" + path);
		properties = new Properties();
		  try {
			  
			  BufferedReader bufferedReader = new BufferedReader(new FileReader(path));
			  properties.load(bufferedReader);
			  url = properties.getProperty("URL");
			  username = properties.getProperty("USERNAME");
			  password = properties.getProperty("PASSWORD");
			  domain = properties.getProperty("DOMAIN");
			  projectId = properties.getProperty("PROJECTID");
			  imageId = properties.getProperty("IAMGEID");
			  networkId = properties.getProperty("NETWORKID");
			  flavorId = properties.getProperty("FLAVORID");
			  
			  
					 
			  logger.info("url:" + url);
			  logger.info("username :" + username);
			  logger.info("domain :" + domain);
			  logger.info("projectId :" + projectId);
			  logger.info("imageId :" + imageId);
			  logger.info("networkId :" + networkId);
			  logger.info("flavorId :" + flavorId);
		  } catch (IOException e) {
		     logger.error(e.getMessage());
		  }
	
	}
	
	// create a vm and allocate a floating ip 
	public VmInfo create(String vmName) throws InterruptedException, IOException {
		logger.info("Start create VM");
		logger.info("vmName:{}",vmName);
		ServerCreate sc = Builders.server().name(vmName).flavor(flavorId)
				.image(imageId)
				.networks(networks).build();	
		// Boot the Server
		Server server = os.compute().servers().boot(sc);
		String serverId = server.getId();
		
		// wait 120s until the server getting active
		for (int i = 0; i < ConstProperties.TIME_TO_WAIT_VM_READY; i++) {
			Thread.sleep(1000);
			server = os.compute().servers().get(serverId);
			if (server.getStatus().name().equals("ACTIVE")) {
				logger.info("Server name:" + server.getName() + "  server id:"  + server.getId() + " is ready");
				break;
			}
			
		}
		String floatingIp = getUnboundIp();
		if(floatingIp == null){
			// create a floating ip and bound it to the server
			List<String> pools = os.compute().floatingIps().getPoolNames();
			FloatingIP ip = os.compute().floatingIps().allocateIP(pools.get(0));
			NetFloatingIP netFloatingIP = os.networking().floatingip().get(ip.getId());
			floatingIp = netFloatingIP.getFloatingIpAddress();
			logger.info("Create a new floating ip " + floatingIp);
			
		}

		ActionResponse response = os.compute().floatingIps().addFloatingIP(server, floatingIp);
		if(response.getCode() == 200){
			logger.info("Bound floating Ip succeed");
		}
		String vncUrl = null;
		VmInfo vmInfo = null;
		try{
			vncUrl = getVncToken(serverId);
			vmInfo = new VmInfo(serverId,vncUrl,server.getName(),floatingIp);
			logger.info(vmInfo.toString());
		}catch(Exception e){
			logger.error(e.getMessage());
		}

		return vmInfo;
	};

	// delete single server by id
	public void deleteById(String id) {
		ActionResponse response = os.compute().servers().delete(id);
		logger.info("  Server id:"  + id + " deleted " + response); 
	};
	
	// delete servers by name
	public void deleteByName(String name) {
		
		 List<? extends Server> servers = os.compute().servers().list();
		 for (Server server : servers) {
			 if(server.getName().equals(name)){
				 ActionResponse response = os.compute().servers().delete(server.getId());
				 if(response.getCode() == 200){
					 logger.info("Server name:" + server.getName() + "  server id:"  + server.getId() + " deleted"  ); 
				 }			 
			 }
		}		
	};
	// delete servers by name
	public void deleteByIp(String ip) {
		
		 List<? extends Server> servers = os.compute().servers().list();
		 for (Server server : servers) {
			 if(server.toString().contains(ip)){
				 ActionResponse response = os.compute().servers().delete(server.getId());
				 if(response.getCode() == 200){
					 logger.info("Server name:" + server.getName() + "  server id:"  + server.getId() + "  ip:" + ip + " deleted"  ); 
				 }
				 
			 }

		}
		
		
	};
	
	// free all the floating ips which are not bounded
	public void freeFloatingIps(){
		 List<? extends FloatingIP> ips = os.compute().floatingIps().list();
		 
		 for (FloatingIP ip : ips) {		
			 if(ip.getFixedIpAddress() == null){
				 os.compute().floatingIps().deallocateIP(ip.getId()) ;
				 logger.info(ip + " has been unlocated");
			 }
		}

	}

	// init the connection to openstack 
	public void init(String configureFile) {
		if(new File(configureFile).exists()){
			loadConfig(configureFile);
		}else{			
			logger.warn("Configure file not exist");	
		}
		os = OSFactory.builderV3().endpoint(url)
				.credentials(username, password, Identifier.byName(domain))
				.scopeToProject(Identifier.byId(projectId))
				.authenticate();
	
		networks.add(networkId);

	};
	public String getUnboundIp(){
		String floatingIp = null;
		 List<? extends FloatingIP> ips = os.compute().floatingIps().list();
		 
		 for (FloatingIP ip : ips) {		
			 if(ip.getFixedIpAddress() == null){
				 NetFloatingIP netFloatingIP = os.networking().floatingip().get(ip.getId());
				 floatingIp = netFloatingIP.getFloatingIpAddress();
				 logger.info("Reuse a floating ip " + floatingIp);
				 return floatingIp;
			 }
		}
		 return floatingIp;

	}

	public void outputVMList(String filename) throws IOException{
		
		FileWriter fw= new FileWriter(new File(filename),true);
		SimpleDateFormat sdf1=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		fw.write(sdf1.format(new Date()) + "\n");
		for(int i=0; i< vmInfoList.size(); i++){
			fw.write(vmInfoList.get(i)+"\n");	
		}
		fw.write("-----------------------------------------------------------------------------\n");	
		fw.close();
		
	}
	
	public String getVncToken(String serverid) throws IOException{
		VNCConsole console = os.compute().servers().getVNCConsole(serverid, Type.NOVNC);
		String vncUrl = console.getURL();
		
		return vncUrl;
		
	}
	public void deleteFromFile(String filename){
		try {
			if(!new File(filename).exists()){
				logger.warn("Delete file not exist");
				return;
			}
			BufferedReader br = new BufferedReader(new FileReader(filename));
			String str = null;
			while((str = br.readLine()) != null){
				String[] ss = str.split("\\s+");
				deleteById(ss[0]);
			}
			br.close();
			
		} catch (FileNotFoundException e) {
			
			logger.error(e.getMessage());
		} catch (IOException e) {
			logger.error(e.getMessage());
		}
		
	}
	public void deleteFromUser(){
		logger.info("Start delete all the vms of the user" + this.username);
		 List<? extends Server> servers = os.compute().servers().list();
		 for (Server server : servers) {
			 deleteById(server.getId());
		 }
		
	}
	public void deleteFromFileByName(String filename){
		try {
			if(!new File(filename).exists()){
				logger.warn("Delete file not exist");
				return;
			}
			BufferedReader br = new BufferedReader(new FileReader(filename));
			String str = null;
			while((str = br.readLine()) != null){
				String[] ss = str.split("\\s+");
				deleteByName(ss[0]);
			}
			br.close();
			
		} catch (FileNotFoundException e) {
			
			logger.error(e.getMessage());
		} catch (IOException e) {
			logger.error(e.getMessage());
		}
		
	}
	public void getVncFromFile(String filename){
		try {
			logger.info("Get vnc urls from the file which contains server ids");
			BufferedReader br = new BufferedReader(new FileReader(filename));
			String str = null;
			String vncUrl = null;
			while((str = br.readLine()) != null){
				String[] ss = str.split("\\s+");
				logger.info("Id:" + ss[0]);
				vncUrl = getVncToken(ss[0]);
				logger.info(str +  " " +  vncUrl);
			}
			br.close();
			
		} catch (FileNotFoundException e) {
			
			logger.error(e.getMessage());
		} catch (IOException e) {
			logger.error(e.getMessage());
		}
		
	}

	public void createVMsFromFile(String filename) {
		
		try {
			logger.info("Create vms from a file which contains the vm names");
			if(!new File(filename).exists()){
				logger.info("Delete file not exist");
				return;
			}
			BufferedReader br = new BufferedReader(new FileReader(filename));
			String str = null;
			while((str = br.readLine()) != null){

				try {
					VmInfo vmInfo = create(str);
					if(vmInfo != null){
						vmInfoList.add(vmInfo);
					}
					
				} catch (InterruptedException e) {
					logger.error(e.getMessage());
				}
			}
			br.close();
			
		} catch (FileNotFoundException e) {
			
			logger.error(e.getMessage());
		} catch (IOException e) {
			logger.error(e.getMessage());
		}
		try {
			outputVmList("result.txt");
		} catch (IOException e) {
	
			logger.error(e.getMessage());
		}
		
	}
	public void outputVmList(String filename) throws IOException{
		FileWriter fw= new FileWriter(new File(filename),true);
		SimpleDateFormat sdf1=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		fw.write(sdf1.format(new Date()) + "\n");
		for (Iterator<VmInfo> iterator = vmInfoList.iterator(); iterator.hasNext();) {
			VmInfo vmInfo = (VmInfo) iterator.next();
			fw.write(vmInfo.toString()+"\n");	
		}
		fw.write("-----------------------------------------------------------------------------\n");	
		fw.close();
		
	}
	public void createAndSaveRedis(String filename) {
		createVMsFromFile(filename);
		 RedisPoolResource instance = RedisPoolResource.getInstance();
		 instance.lpushVmList(vmInfoList);

		
	}
	public void main(String[] args) throws InterruptedException,IOException {
		try {
			if(args.length != 3){
				logger.error("Parameter error!!!");
			}
			for (int i = 0; i < args.length; i++) {
				logger.info(args[i]);
			}
	
			
			OpenstackUtil openUtil = new OpenstackUtil();
			openUtil.init(args[0]);
			//openUtil.init("config.properties");
			switch (Integer.parseInt(args[1])) {
			case 1:
				logger.info("Create single VM");
				openUtil.create(args[2]);
				break;
			case 2:
				logger.info("Delete VM by name");
				openUtil.deleteByName(args[2]);
				break;
			case 3:
				logger.info("Delete VM by id");
				openUtil.deleteById(args[2]);
				break;
			case 4:
				logger.info("Delete VM by ip");
				openUtil.deleteByIp(args[2]);
				break;
			case 5:
				logger.info("Get vnc token url");
				logger.info(openUtil.getVncToken(args[2]));
				break;
			case 6:
				logger.info("Delete VMs from file contains id list");
				openUtil.deleteFromFile(args[2]);

				break;
			case 7:
				logger.info("Get vnc tokens from file contains id list");
				openUtil.getVncFromFile(args[2]);

				break;
			case 8:
				logger.info("Create vms from file contains vm names");
				openUtil.createVMsFromFile(args[2]);
				openUtil.outputVMList("result.txt");
				break;
			case 9:
				logger.info("9");
				break;
			case 10:
				logger.info("10");
				break;
			default:
				break;

			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
